/*
 * sudoku.cpp
 *
 *  Created on: 15/02/2010
 *      Author: rromero
 */

#include "sudoku.h"

sudoku::sudoku(const string &file) : _tablero(vector<vector<celda> >(9, vector<celda>(9))) {
	string basura;
	unsigned int dato;

	ifstream fich(file.c_str());
	if (fich.is_open()) {
		fich >> basura;

	    unsigned int fila = 1;
	    unsigned int columna = 1;

	    while ((fila < 10) and (columna < 10)) {
	    	fich >> basura;
	    	// string to int
	    	istringstream buffer(basura);
	    	dato=0;
	    	buffer >> dato;
	    	if ((dato >= 1) and (dato <= 9)) {
	    		bool res = _tablero[fila-1][columna-1].fijar_valor(dato, true);
	    		if (!res) {
	    			cout << "Problemas con el tablero..." << endl;
	    		}
	    	}
	    	++columna;
	    	if (columna == 10) {
	    		columna = 1;
	    		++fila;
	    	}
	    }

	    fich.close();
	  }
	else {
		cout << "Imposible abrir fichero " << file << endl;
	}
}

bool sudoku::fijar_valor(const unsigned int &fila, const unsigned int &columna, const unsigned int &valor){

	bool fijar = false;
	
	if ((fila > 0) and (fila < 10) and (columna > 0) and (columna < 10) and (valor > 0) and (valor < 10)) {
		if (es_factible(fila,columna,valor)) {
			celda celda_aux = _tablero[fila-1][columna-1];
			fijar = _tablero[fila-1][columna-1].fijar_valor(valor, false);
			if (fijar) {
				list<pair<pair<unsigned int, unsigned int>, celda> > lista_aux;
				
				//Borrar valor en opciones
				//Fila
				for (unsigned int i = 1; i < 10; i++) {
   					set<unsigned int> set_aux = _tablero[fila-1][i].opciones();
   					if (set_aux.find(valor) != set_aux.end()) {
   						lista_aux.push_back(pair<pair<unsigned int, unsigned int>, celda>(pair<unsigned int, unsigned int>(fila-1,i),_tablero[fila-1][i]));
   						_tablero[fila-1][i].borrar_opcion(valor);
   					}
   				}
				//Columna
				for (unsigned int i = 1; i < 10; ++i) {
   					set<unsigned int> set_aux = _tablero[i][columna-1].opciones();
   					if (set_aux.find(valor) != set_aux.end()) {
   						lista_aux.push_back(pair<pair<unsigned int, unsigned int>, celda>(pair<unsigned int, unsigned int>(i, columna-1),_tablero[i][columna-1]));
   					   	_tablero[i][columna-1].borrar_opcion(valor);
   					}
   				}
				//Bloque
				for (unsigned int i = 0; i < 3; i++)
    				for (unsigned int j = 0; j < 3; j++) {
    					unsigned int i_fila = (unsigned int)((fila-1) / 3) * 3;
    					unsigned int i_columna = (unsigned int)((columna-1) / 3) * 3;
    					set<unsigned int> set_aux = _tablero[i_fila+i][i_columna+j].opciones();
    					if (set_aux.find(valor) != set_aux.end()) {
    						lista_aux.push_back(pair<pair<unsigned int, unsigned int>, celda>(pair<unsigned int, unsigned int>(i_fila+i, i_columna+j),_tablero[i_fila+i][i_columna+j]));
    					   	_tablero[i_fila+i][i_columna+j].borrar_opcion(valor);
    					}
    				}
    				
				//La jugada queda almacenada
				lista_aux.push_back(pair<pair<unsigned int, unsigned int>, celda>(pair<unsigned int, unsigned int>(fila-1,columna-1),celda_aux));
				_jugadas.push(lista_aux);
						
			}
		}	
	}
	
	return fijar;
}

void sudoku::borrar_valor(const unsigned int &fila, const unsigned int &columna){
	
	_tablero[fila-1][columna-1].borrar_valor();

}

bool sudoku::finalizado() const{
	
}

list<unsigned int> sudoku::opciones(const unsigned int &fila, const unsigned int &columna) const{
	
	list<unsigned int> lista_ui;
	set <unsigned int> set_aux = _tablero[fila-1][columna-1].opciones();
	
	set <unsigned int>::iterator it;
	for(it = aux.begin();it !=aux.end();++it)
		lista_ui.insert(*it);
			
	return lista_ui;
	
}

bool sudoku::nueva_opcion(const unsigned int &fila, const unsigned int &columna, const unsigned int &valor){
	
}

bool sudoku::borrar_opcion(const unsigned int &fila, const unsigned int &columna, const unsigned int &valor){
	

}

const celda& sudoku::valor(const unsigned int &fila, const unsigned int &columna) const{


}

bool sudoku::es_factible(const unsigned int &fila, const unsigned int &columna, const unsigned int &valor) const{
	
bool factible = true;

	//Fila
	for(unsigned int i = 0; ((i<9) and (factible)); i++){
    
		factible = _tablero[fila-1][i].valor() != valor ;
    
    }
    
    //Columna
    for(unsigned int i = 0; ((i<9) and (factible)); i++){
    
		factible = _tablero[i][columna-1].valor() != valor ;
    
    }
    
    //Bloque
    unsigned int i_fila = (unsigned int)((fila-1) / 3) * 3;
	unsigned int i_columna = (unsigned int)((columna-1) / 3) * 3;
	for (unsigned int i = 0; ((i < 3) and (factible)); i++) {
		for (unsigned int j = 0; ((j < 3) and (factible)); j++) {
			factible = (_tablero[i_fila+i][i_columna+j].valor() != valor);
		}
	}
  
	return factible;
    
}

bool sudoku::undo(){
	

}

ostream& operator<<(ostream& os, const sudoku& c){

os << "Tablero:" << endl;
	for (unsigned int i = 1; i < 10; i++) {
		for (unsigned int j = 1; j < 10; j++) {
			cout << c.valor(i,j);
		}
		os << endl;
	}

	os << "Opciones:" << endl;
	for (unsigned int i = 1; i < 10; i++) {
		for (unsigned int j = 1; j < 10; j++) {
			list<unsigned int> lista = c.opciones(i,j);
			if (!lista.empty()) {
				os << "Fila: " << i << endl;
				os << "Columna: " << j << endl;
				for (list<unsigned int>::const_iterator it = lista.begin(); it != lista.end(); ++it)
					os << *it << " ";
				os << endl;
			}
		}
	}

	return os;
}



